package org.light.limitedverb;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Field;
import org.light.domain.Method;
import org.light.domain.Signature;
import org.light.domain.Statement;
import org.light.domain.Type;
import org.light.exception.ValidateException;
import org.light.utils.DomainTokenUtil;
import org.light.utils.InterVarUtil;
import org.light.utils.StringUtil;
import org.light.utils.TableStringUtil;
import org.light.utils.WriteableUtil;

public class CountSearchByFieldsRecords extends NoControllerVerb {
	@Override
	public Method generateDaoImplMethod() throws Exception {
		if (this.denied)
			return null;
		else {
			if ("pgsql".equalsIgnoreCase(this.dbType)||"postgresql".equalsIgnoreCase(this.dbType)) {
				org.light.pgsql.verb.CountSearchByFieldsRecords sn = new org.light.pgsql.verb.CountSearchByFieldsRecords(this.domain);
				return sn.generateDaoImplMethod();
			}else {
				Method method = new Method();
				method.setStandardName("countSearch" + domain.getCapFirstPlural() + "ByFieldsRecords");
				method.setNoContainer(true);
				List<Writeable> list = new ArrayList<Writeable>();
				list.add(new Statement(100L, 1, "<select id=\"" + method.getLowerFirstMethodName() + "\" parameterType=\""
						+ this.domain.getFullName() + "\" resultType=\"int\">"));
				list.add(new Statement(200L, 2, "select count(*) countSum from " + domain.getDbPrefix()
						+ TableStringUtil.domainNametoTableName(domain)));
				list.add(new Statement(300L, 2, "where 1=1 "));
				long serial = 400L;
				Set<Field> fields = this.domain.getFieldsWithoutId();
				for (Field f : fields) {
					if (!deniedFields.contains(f)) {
						if (f.getFieldType().equalsIgnoreCase("string")) {
							list.add(new Statement(serial, 2, "<if test=\"" + f.getLowerFirstFieldName() + "!=null and "
									+ f.getLowerFirstFieldName() + "!='' \">"));
							list.add(new Statement(serial + 100, 3,
									"and " + DomainTokenUtil.changeDomainFieldtoTableColum(f.getLowerFirstFieldName())
											+ " LIKE CONCAT(CONCAT('%', #{" + f.getLowerFirstFieldName() + "}),'%')"));
						} else if ("datetime".equalsIgnoreCase(f.getFieldType())||"date".equalsIgnoreCase(f.getFieldType())){
							list.add(new Statement(serial, 2, "<if test=\"" + f.getLowerFirstFieldName() + "!=null\">"));
							list.add(new Statement(serial + 100, 3,
									"and date(" + DomainTokenUtil.changeDomainFieldtoTableColum(f.getLowerFirstFieldName()) + ") = date(#{"
											+ f.getLowerFirstFieldName() + "}) "));
						} else {
							list.add(new Statement(serial, 2, "<if test=\"" + f.getLowerFirstFieldName() + "!=null\">"));
							list.add(new Statement(serial + 100, 3,
									"and " + DomainTokenUtil.changeDomainFieldtoTableColum(f.getLowerFirstFieldName()) + " = #{"
											+ f.getLowerFirstFieldName() + "}"));
						}
						list.add(new Statement(serial + 200, 2, "</if>"));
						serial += 300L;
					}
				}
				list.add(new Statement(serial, 1, "</select>"));
				method.setMethodStatementList(WriteableUtil.merge(list));
				return method;
			}
		}
	}

	@Override
	public Method generateDaoMethodDefinition() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName("countSearch" + this.domain.getCapFirstPlural() + "ByFieldsRecords");
			method.setReturnType(new Type("Integer"));
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType(),
					this.domain.getPackageToken()));
			method.setThrowException(true);
			return method;
		}
	}

	@Override
	public Method generateServiceMethodDefinition() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName("countSearch" + this.domain.getCapFirstPlural() + "ByFieldsRecords");
			method.setReturnType(new Type("Integer"));
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType()));
			method.setThrowException(true);

			return method;
		}
	}

	@Override
	public Method generateServiceImplMethod() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName("countSearch" + this.domain.getCapFirstPlural() + "ByFieldsRecords");
			method.setReturnType(new Type("Integer"));
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDaoSuffix() + "."
					+ this.domain.getStandardName() + "Dao");
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getServiceSuffix() + "."
					+ this.domain.getStandardName() + "Service");
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType()));
			method.setThrowException(true);
			method.addMetaData("Override");

			Method daomethod = this.generateDaoMethodDefinition();
			List<Writeable> list = new ArrayList<Writeable>();
			list.add(new Statement(1000L, 2, "return "
					+ daomethod.generateStandardServiceImplCallString(InterVarUtil.DB.dao.getVarName()) + ";"));
			method.setMethodStatementList(WriteableUtil.merge(list));

			return method;
		}
	}

	public CountSearchByFieldsRecords(Domain domain) throws ValidateException {
		super();
		this.domain = domain;
		this.dbType = "MariaDB";
		this.denied = domain.isVerbDenied("SearchByFieldsByPage");
		this.verbName = "countSearch" + this.domain.getCapFirstPlural() + "ByFieldsRecords";
	}
	
	public CountSearchByFieldsRecords(Domain domain,String dbType) throws ValidateException {
		super();
		this.domain = domain;
		this.dbType = dbType;
		this.denied = domain.isVerbDenied("SearchByFieldsByPage");
		this.verbName = "countSearch" + this.domain.getCapFirstPlural() + "ByFieldsRecords";
	}

	public CountSearchByFieldsRecords() {
		super();
		this.dbType = "MariaDB";
	}
	
	public CountSearchByFieldsRecords(String dbType) {
		super();
		this.dbType = dbType;
	}

	@Override
	public Method generateDummyDaoImplMethod() throws Exception {
		if (this.denied)
			return null;
		else {
			Method method = new Method();
			method.setStandardName(StringUtil.lowerFirst(this.getVerbName()));
			method.setReturnType(new Type("Integer"));
			method.addAdditionalImport(this.domain.getPackageToken() + ".utils.StringUtil");
			method.addSignature(new Signature(1, this.domain.getLowerFirstDomainName(), this.domain.getType(),
					this.domain.getPackageToken()));
			method.addAdditionalImport(this.domain.getPackageToken() + "." + this.domain.getDomainSuffix() + "."
					+ this.domain.getCapFirstDomainNameWithSuffix());
			method.setThrowException(true);
			
			List<Writeable> sList = new ArrayList<Writeable>();
			long serial = 1000L;			
			sList.add(new Statement(serial+1000L,2,"List<"+this.domain.getCapFirstDomainNameWithSuffix()+"> result = new ArrayList<>();"));
			sList.add(new Statement(serial+2000L,2,"for ("+this.domain.getCapFirstDomainNameWithSuffix()+" raw"+this.domain.getLowerFirstDomainName()+" : db){"));
			sList.add(new Statement(serial+3000L,3,"boolean matches = true;"));
			serial += 4000L;
			for (Field f: this.domain.getSearchFields()) {
				if (! deniedFields.contains(f)) {
					if (f instanceof Dropdown) {
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("String".equalsIgnoreCase(f.getFieldType())){					
						sList.add(new Statement(serial,3,"if (!StringUtil.isBlank("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().contains("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("int".equals(f.getFieldType())||"Integer".equals(f.getFieldType())||"long".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("float".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (Math.abs(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() - "+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) > 0.0001) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("float".equalsIgnoreCase(f.getFieldType())||"double".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (Math.abs(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() - "+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) > 0.0001) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("boolean".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (!raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().equals("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("datetime".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+500L,4,"SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");"));
						sList.add(new Statement(serial+1000L,4,"if (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() == null || (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null && sdf.format(raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()).compareTo(sdf.format("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"())) != 0)) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					} else if ("date".equalsIgnoreCase(f.getFieldType())){
						sList.add(new Statement(serial,3,"if ("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null) {"));
						sList.add(new Statement(serial+1000L,4,"if (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() == null || (raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"() != null && raw"+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"().compareTo("+this.domain.getLowerFirstDomainName()+".get"+f.getCapFirstFieldName()+"()) != 0)) matches = false;"));
						sList.add(new Statement(serial+2000L,3,"}"));
					}					
					serial += 3000L;
				}
			}
			sList.add(new Statement(serial,3,"if (matches) result.add(raw"+this.domain.getLowerFirstDomainName()+");"));
			sList.add(new Statement(serial+1000L,2,"}"));
			sList.add(new Statement(serial+2000L,2,"return result.size();"));
			method.setMethodStatementList(WriteableUtil.merge(sList));
			return method;
		}
	}

}
